import React from 'react';
import exceed from 'utils/apimap';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actions from '../../actions/index';
import RepoOverviewInfo from '../repoOverviewInfo';
import { Search, Button, Balloon } from '@teamix/ui';
import { Body, BodyContent, Content, ButtonIcon, SideBar } from '@alife/devops-ui';
import TreeLeft from './treeLeft';
import FilterTreeLeft from './filterLeftTree';
import Blob from './blob';
import RightTable from './routes/table.jsx';
import CommitInfoMedia from 'components/commitInfoMedia';
import UploadFile from './dialog/uploadFile';
import ProjectBreadcrumb from 'components/pathBreadcrumb/breadcrumb.jsx';
import TreeRight from './treeRight';
import NewFiles from './../newFiles';
import Empty from '../empty';
import EditorFiles from './../editorFiles';
import BranchAndTagSelect from 'components/branchAndTagSelect';
import CloneBtn from '../repoOverviewInfo/cloneBtn';
import { ENUM } from 'utils/constants';
import utils from 'utils';
import track, { Perf } from 'utils/track';
import AddOrUploadFile from './addOrUploadFile';
import WebIdeBtn from './components/webIdeBtn';
import { getWebIdeUrl } from 'api';
import { getFeature } from 'utils/features';
import './index.scss';
import intl from '../../../../../../../../locale';
import { navigate, getPathWithNoRootPath, navigateOpen } from 'utils/router';

const { ctrlTxt } = ENUM.getOSKeyMap();

// const { user_role } = window.FORCE.organization;
class FileContent extends React.Component {
  static propTypes = {
    blob: PropTypes.arrayOf(PropTypes.object),
  };

  static defaultProps = {
    blob: [],
  };

  constructor(props) {
    super(props);
    this.state = {
      isShowSearch: false,
      filterText: '',
      isDialogVisible: false,
      // 点击上传时的路径
      filePath: '',
    };
    this.container = null;
    this.imageObserver = null;
    this.projectNavTree = React.createRef();
  }

  onDialogOpen = () => {
    this.setState({
      isDialogVisible: true,
    });
  };

  onDialogClose = () => {
    this.setState({
      isDialogVisible: false,
    });
  };

  componentDidMount() {
    const { selectedType } = this.props;

    const { resourceSubject = {} } = window.FORCE;
    const { revisionType, revision } = resourceSubject;

    if (revisionType === 'branch') {
      this.props.getProtectedBranchInfo(revision);
    }

    this.props.getServiceSettings(() => {
      // 初次获取右侧的文件或树
      if (selectedType === 'blob') {
        this.props.getBlobAndCommitWithPath();
      }
    });
    this.onDrag();
    window.addEventListener('resize', this.onDrag);
    if (this.props.genWatermarkimage) {
      this.backageImageMutationObserver(); // 这个是水印相关的函数
    }
  }

  // 加载新 blob 时，需调 getBlobAndCommitWithPath
  componentDidUpdate(prevProps) {
    if (this.props.selectedType === 'blob' && prevProps.resourcePath !== this.props.resourcePath) {
      this.props.getBlobAndCommitWithPath();
    }
    const wrapEle = document.querySelector('.teamix-layout-side-bar-content');
    if (wrapEle) {
      this.projectNavTree.current.style.height = `${wrapEle.offsetHeight - 94 }px`;
    }
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.onDrag);
    this.imageObserver && this.imageObserver.disconnect();
  }

  backageImageMutationObserver = () => {
    // 选择需要观察变动的节点
    const targetNode = this.container || document.querySelector('.add_watemark_class');
    // 观察器的配置（需要观察什么变动）
    const config = { attributes: true, childList: true, subtree: true };
    // 当观察到变动时执行的回调函数
    const callback = (mutationsList) => {
      // Use traditional 'for loops' for IE 11
      for (const mutation of mutationsList) {
        if (mutation.type === 'attributes') {
          targetNode.style.backgroundImage = utils.isGenWatermarkimage(
            this.props.genWatermarkimage,
          );
        }
      }
    };
    // 创建一个观察器实例并传入回调函数
    this.imageObserver = new MutationObserver(callback);
    // 以上述配置开始观察目标节点
    targetNode && this.imageObserver.observe(targetNode, config);
  };

  getProjectInfoFromPageInfo = () => {
    const { pathResource, resourceSubject } = this.props.pageInfo || {};
    const isExist = pathResource.isExist === 'true';
    const isEmpty = pathResource.isEmpty === 'true';
    return {
      isEmpty,
      isExist,
      role: pathResource.role,
      pathResource,
      resourceSubject,
    };
  };

  onTooLargeTipMessageClose = () => {
    utils.setCachedData('project-too-large-message', 'close');
  };

  goWebIde = (e, path) => {
    const { resourceSubject } = window.FORCE;
    const { revisionType } = resourceSubject;
    const { projectInfo } = this.props;
    const admin_setting_language = projectInfo && projectInfo.admin_setting_language;
    const template = utils.getAdminSettingLanguage(admin_setting_language);
    e.preventDefault();
    track({
      action: 'goto_webide',
      page: 'Repo-Files',
    });
    getWebIdeUrl({
      filepath: path,
      branch: revisionType === 'branch' ? resourceSubject.revision : '',
      commit: revisionType === 'sha1' ? resourceSubject.revision : '',
      line: '',
      column: '',
      type: template,
      merge_commit: '',
      mergerequestId: '',
    })
      .then((result) => {
        const url = result.endpoint;
        navigateOpen(url);
      })
      .catch((err) => {
        console.error(err);
      });
  };

  renderContent = () => {
    const { selectedType, lastCommit, resourceType, isLoadingLastCommit, projectInfo } = this.props;
    // 直接访问路径需要后端配置
    if (selectedType === 'tree') {
      return (
        <>
          <RightTable />
          <Perf page={'Repo-Files'} />
        </>
      );
    }
    if (selectedType === 'blob') {
      const { pathResource } = window.FORCE;
      const { renderType, resourcePath, isInitedLeftTree, treeData, ipSetting } = this.props;
      const { isArchive } = pathResource;
      return (
        <div className="project-file-content-body">
          <div className="overview-info">
            <ProjectBreadcrumb isHeader {...this.props} />
            <div>
              {isArchive === 'false' &&
              renderType === 'TEXT' &&
              getFeature('WebIDE.entrance.file') &&
              isInitedLeftTree &&
              treeData.length ? (
                <WebIdeBtn
                  tooltipText={intl.get({
                    id: 'code-assets.containers.content.blob.WebideCanOnlyBePerformed',
                    defaultMessage: '只有分支下才可以进行 WebIDE 操作',
                  })}
                  type="normal"
                  className="file-icon-margin-left"
                  component="a"
                  project_clone_download={this.props.project_clone_download}
                  onClick={(e) => {
                    this.goWebIde(e, resourcePath);
                  }}
                  ipSetting={ipSetting}
                  style={{ marginRight: 8 }}
                >
                  WebIDE
                </WebIdeBtn>
              ) : null}
              <CloneBtn {...this.props} />
            </div>
          </div>
          <div className="file-commit-container">
            <CommitInfoMedia isLoading={isLoadingLastCommit} commitInfo={lastCommit} noBuildTag />
          </div>
          <div className="project-file-content-blob">
            <Blob {...this.props} resourcePath={utils.filepathEncodeURI(this.props.resourcePath)} />
          </div>
        </div>
      );
    }
    if (selectedType === 'new') {
      return (
        <div>
          <NewFiles {...this.props} />
          <Perf page={'Repo-Files'} />
        </div>
      );
    }
    if (selectedType === 'edit') {
      return (
        <div>
          <EditorFiles {...this.props} genWatermarkimage={this.props.genWatermarkimage} />
          <Perf page={'Repo-Files'} />
        </div>
      );
    }
    if (selectedType !== '') {
      return null;
    }
    // 首页才显示，此时selectedType === ''
    return (
      <>
        <RepoOverviewInfo {...this.props} foldBtn={this.state.foldBtn} />
        <div className="project-file-content-body">
          <div className="file-commit-container">
            <CommitInfoMedia
              commitInfo={lastCommit}
              isLoading={isLoadingLastCommit}
              projectInfo={projectInfo}
            />
          </div>
          <div className="project-file-content-blob">
            {resourceType === 'blob' ? (
              <Blob
                {...this.props}
                resourcePath={utils.filepathEncodeURI(this.props.resourcePath)}
              />
            ) : (
              <TreeRight {...this.props} />
            )}
          </div>
        </div>
      </>
    );
  };

  goNew = () => {
    const { resourceSubject, pathResource } = this.getProjectInfoFromPageInfo();
    const revision = resourceSubject.revision || 'master';
    navigate(`/${pathResource.fullPath}/new/${utils.revisionEncodeURI(revision)}?isMaster=1`);
    this.props.updateSetSelectedType({
      resourceSubject: {
        subject: 'new',
        path: '',
      },
    });
  };

  toggleInput = (value) => {
    if (value) {
      this.setState({
        isShowSearch: value,
      });
    } else {
      this.setState({
        isShowSearch: value,
        filterText: '',
      });
    }
    this.setState({
      isShowSearch: value,
    });
  };

  changeFilterText = (value) => {
    this.setState({
      filterText: value.trim(),
    });
  };

  // 切換分支
  handleChangeBranch = (value) => {
    const { pathResource, resourceSubject } = this.getProjectInfoFromPageInfo();
    const { resourceType } = this.props;
    const newRevision = utils.revisionEncodeURI(value);
    // 如果当前路径里有revision（分支或tag），则替换成新选的；否则直接跳转到/tree/revision
    // 切换分支

    if (
      window.location.pathname.indexOf(
        `/${pathResource.fullPath}/${resourceType}/${resourceSubject.revision}`,
      ) !== -1
    ) {
      const url = window.location.pathname.replace(
        `/${pathResource.fullPath}/${resourceType}/${resourceSubject.revision}`,
        `/${pathResource.fullPath}/${resourceType}/${newRevision}`,
      );

      exceed
        .fetch({
          api: 'spa.path',
          data: {
            path: getPathWithNoRootPath(url),
          },
        })
        .then((res) => {
          if (res.success) {
            navigate(getPathWithNoRootPath(url), {
              state: { forceUpdate: true },
            });
          } else {
            navigate(`/${pathResource.fullPath}/tree/${newRevision}`, {
              state: {
                forceUpdate: true,
                toastWarning: intl.get(
                  {
                    id: 'code-assets.containers.content.ResourcesubjectpathCannotBeFoundIn',
                    defaultMessage: '{value}分支上找不到 "{resourceSubjectPath}"',
                  },
                  { value, resourceSubjectPath: resourceSubject.path },
                ),
              },
            });
          }
        })
        .fail(() => {
          navigate(`/${pathResource.fullPath}/tree/${newRevision}`, {
            state: { forceUpdate: true },
          });
        });
    } else {
      navigate(`/${pathResource.fullPath}/tree/${newRevision}`, {
        state: { forceUpdate: true },
      });
    }
  };

  onCompare = () => {
    const { pathResource, resourceSubject } = window.FORCE;
    navigate(
      `/${pathResource.fullPath}/compare?from=${encodeURIComponent(
        pathResource.defaultBranch,
      )}&to=${encodeURIComponent(resourceSubject.revision)}&tab=branches`,
    );
  };

  onDrag = () => {
    const dom = document.querySelector('.project-file-layout-content');
    if (dom) {
      const { width } = dom.getBoundingClientRect();
      if (width < 800) {
        this.setState({
          foldBtn: true,
        });
      } else {
        this.setState({
          foldBtn: false,
        });
      }
    }
  };

  render() {
    const { isEmpty } = this.getProjectInfoFromPageInfo();
    const { selectedType, genWatermarkimage } = this.props;
    const { filePath } = this.state;
    const backImage = utils.isGenWatermarkimage(genWatermarkimage);

    if (isEmpty && !selectedType) {
      return (
        <Body>
          <BodyContent>
            <Content>
              <RepoOverviewInfo isEmptyProject {...this.props} />
              <Empty {...this.props} />
              <Perf page={'Repo-Files'} />
            </Content>
          </BodyContent>
        </Body>
      );
    }

    const isTooLarge = utils.isTooLarge(this.props.pageInfo.pathResource);

    return (
      <Body
        className="project-file-wrapper add_watemark_class"
        style={{ backgroundImage: backImage || '' }}
        ref={(el) => {
          this.container = el;
        }}
      >
        {!isEmpty && (
          <SideBar
            noPadding
            draggable
            onDrag={this.onDrag}
            size="medium"
            style={{ width: 280, minWidth: 275, maxWidth: '50%' }}
          >
            <div
              className="project-nav"
              ref={(r) => {
                this.projectNav = r;
              }}
              style={{
                // FIXME FIX ME
                // width: '300px',
                // top: isTooLarge ? '131px' : '92px',
                // minHeight: 'calc(100% - 40px)',
                backgroundColor: backImage ? 'transparent' : '#fff',
              }}
            >
              <div
                className="project-nav-top"
                style={{ display: window.FORCE.pathResource.isEmpty === 'true' ? 'none' : 'flex' }}
              >
                {this.state.isShowSearch ? (
                  <div style={{ display: 'flex', alignItems: 'center' }}>
                    <Search
                      shape="simple"
                      autoFocus
                      placeholder={intl.get({
                        id: 'code-assets.containers.content.Search',
                        defaultMessage: '搜索',
                      })}
                      value={this.state.filterText}
                      onChange={this.changeFilterText}
                      className="project-nav-top-search-input"
                    />

                    <Button
                      type="primary"
                      size="small"
                      text
                      onClick={() => {
                        this.toggleInput(false);
                      }}
                    >
                      {intl.get({
                        id: 'code-assets.containers.content.Cancel',
                        defaultMessage: '取消',
                      })}
                    </Button>
                  </div>
                ) : (
                  <>
                    <div>
                      <BranchAndTagSelect {...this.props} onChange={this.handleChangeBranch} />
                    </div>
                    <div className="project-nav-top-right">
                      <Balloon.Tooltip
                        align="t"
                        trigger={
                          <ButtonIcon
                            name="search-line"
                            onClick={() => {
                              this.toggleInput(true);
                            }}
                          />
                        }
                      >
                        {intl.get({
                          id: 'code-assets.containers.content.SearchForObjects',
                          defaultMessage: '搜索文件',
                        })}
                        <br /> {ctrlTxt} + /
                      </Balloon.Tooltip>
                      <Balloon.Tooltip
                        align="t"
                        trigger={
                          <ButtonIcon
                            name="codecompare-line"
                            onClick={() => {
                              this.onCompare();
                            }}
                          />
                        }
                      >
                        {intl.get({
                          id: 'code-assets.containers.content.Comparison',
                          defaultMessage: '比较',
                        })}
                      </Balloon.Tooltip>
                      <AddOrUploadFile
                        onUploadDialogOpen={() => {
                          this.setState(
                            {
                              filePath: '',
                            },

                            () => {
                              this.onDialogOpen();
                            },
                          );
                        }}
                        size="medium"
                        {...this.props}
                      />

                      {this.state.isDialogVisible ? (
                        <UploadFile
                          {...this.props}
                          // 有当前路径使用当前路径，否则使用this.props.resourcePath
                          resourcePath={filePath || this.props.resourcePath}
                          closeModal={() => {
                            this.setState({
                              filePath: '',
                            });

                            this.onDialogClose();
                          }}
                          // filePath为'',则是根目录创建
                          isMaster={filePath ? 0 : 1}
                          isDialogVisible={this.state.isDialogVisible}
                        />
                      ) : null}
                    </div>
                  </>
                )}
              </div>
              <div
                className="project-nav-tree"
                style={{ height: `calc(100% - ${isTooLarge ? '145' : '103'}px)` }}
                ref={this.projectNavTree}
              >
                {this.state.isShowSearch ? (
                  <FilterTreeLeft {...this.props} filterText={this.state.filterText} />
                ) : (
                  <TreeLeft
                    {...this.props}
                    projectNav={this.projectNav}
                    isUploadDialogVisible={this.state.isDialogVisible}
                    onUploadDialogOpen={(curFilePath) => {
                      this.setState(
                        {
                          filePath: curFilePath,
                        },

                        () => {
                          this.setState({
                            isDialogVisible: true,
                          });
                        },
                      );
                    }}
                  />
                )}
              </div>
            </div>
          </SideBar>
        )}

        <BodyContent>
          <Content className="project-file-layout-content">
            <div className={isEmpty ? 'project-content' : 'project-file-content'}>
              {this.renderContent()}
            </div>
          </Content>
        </BodyContent>
      </Body>
    );
  }
}

export default connect(
  (state) => {
    return {
      ...state.project.projectFiles,
      projectInfo: state.project.root.projectInfo,
      pageInfo: state.root.pageInfo,
      lastMirrorSyncRecord: state.project.root.lastMirrorSyncRecord,
      mirrorSyncSetting: state.project.root.mirrorSyncSetting,
      genWatermarkimage: state.project.root.genWatermarkimage,
    };
  },
  (dispatch) => bindActionCreators(actions, dispatch),
)(FileContent);
